package cn.suimg.neo4j.service.other;

import cn.suimg.neo4j.bean.*;
import cn.suimg.neo4j.dto.MusicDownloadInfo;
import cn.suimg.neo4j.dto.SongDTO;
import cn.suimg.neo4j.dto.SongListShare;
import cn.suimg.neo4j.redis.CacheKeys;
import cn.suimg.neo4j.redis.CacheOperator;
import cn.suimg.neo4j.util.*;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.BiFunction;

import static cn.suimg.neo4j.config.Constant.*;


@Data
@Slf4j
@Service
@ConfigurationProperties(prefix = "cn.suimg.kugou")
public class KugouService {

    /**
     * 酷狗账户的用户名
     */
    private String username;

    /**
     * 酷狗账户的密码
     */
    private String password;

    /**
     * Redis Handler
     */
    @Resource
    private CacheOperator cacheOperator;

    private BiFunction<JSONObject,String,String> queryMVUrl = (jsonObject, type) -> {
        try{
            return jsonObject.getJSONObject(type).getString("downurl");
        }catch (RuntimeException ignored){}
        return null;
    };

    /**
     * 搜索歌词
     * @param name 歌曲名字/关键字
     * @param hash 歌曲hash值
     * @param duration 持续时间(单位:秒)
     * @return Base64编码的lrc歌词
     */
    @Cacheable("KugouService")
    public String searchLyric(String name,String hash,Integer duration){
        String response = HttpClientUtil.getData(KUGOU_SEARCH_LYRIC_URL,duration,hash, CommonUtil.urlEncode(name));
        JSONObject search = JSONObject.parseObject(response);
        if(search.getInteger("status") == 200){
            JSONObject candidate = search.getJSONArray("candidates").getJSONObject(0);
            String data = HttpClientUtil.getData(KUGOU_DOWNLOAD_LYRIC_URL, candidate.getString("accesskey"), candidate.getIntValue("id"));
            return JSONObject.parseObject(data).getString("content");
        }
        return "5pqC5peg5q2M6K+N";
    }

    /**
     * 搜索歌手写真
     * @param hash 歌曲的hash值
     * @return 歌手写真列表
     */
    @Cacheable("KugouService")
    public List<SingerImage> searchSingerImage(String hash){
        Map<String,Object> entity = new HashMap<String, Object>(){{
            put("appkey","p9hbDHNFkGE74FcMnYSvojEOAYbwFY8j");
            put("clienttime",System.currentTimeMillis());
            put("mid",KUGOU_CONFIG_MID);
            put("data",
                    new ArrayList<Object>(){{
                        add(
                                new HashMap<String,Object>(){{
                                    put("hash",hash);
                                    put("audio_id","");
                                    put("filename","");
                                }}
                        );
                    }}

            );
            put("clientver",295);
            put("key", EncryptUtil.md5(hash + "kgcloudv2"));
            put("type","3,4");
            put("appid",KUGOU_CONFIG_APP_ID);
        }};
        String response = HttpClientUtil.postJson(KUGOU_SEARCH_SINGER_IMAGE_URL,entity);
        List<SingerImage> imageList = new ArrayList<>();

        //服务接口有可能会出现短暂的问题1秒后重试
        JSONObject jsonObject;
        try{
            jsonObject = JSONObject.parseObject(response);
        }catch (JSONException e){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ignored) { }
            return searchSingerImage(hash);
        }

        try {
            jsonObject.getJSONArray("data").getJSONArray(0)
                    .stream()
                    .map(obj -> (JSONObject) obj)
                    .forEach(item -> {
                        JSONObject imgs = item.getJSONObject("imgs");
                        try {
                            imgs.getJSONArray("3").forEach(img0 -> {
                                JSONObject img = (JSONObject) img0;
                                SingerImage image = new SingerImage();
                                image.setSingerId(item.getIntValue("author_id"));
                                image.setHash(img.getString("file_hash"));
                                image.setDownloadUrl(img.getString("sizable_portrait").replace("http://singerimg.kugou.com/","https://imgessl.kugou.com/"));
                                image.setType("PC");
                                imageList.add(image);
                            });
                        } catch (RuntimeException ignored) {}
                        try {
                            imgs.getJSONArray("4").forEach(img0 -> {
                                JSONObject img = (JSONObject) img0;
                                SingerImage image = new SingerImage();
                                image.setSingerId(item.getIntValue("author_id"));
                                image.setHash(img.getString("file_hash"));
                                image.setDownloadUrl(img.getString("sizable_portrait").replace("http://imge.kugou.com/","https://imgessl.kugou.com/"));
                                image.setType("MB");
                                imageList.add(image);
                            });
                        } catch (RuntimeException ignored) {}

                    });
        }catch (ClassCastException ignored){}
        return imageList;
    }

    /**
     * 查询歌手ID
     * @param name
     * @return
     */
    @Cacheable("KugouService")
    public Integer querySingerIdByName(String name){
        String response = HttpClientUtil.getData(KUGOU_SEARCH_SINGER_ID_URL, CommonUtil.urlEncode(name));
        JSONObject json = JSONObject.parseObject(response);
        if(json.getInteger("status") == 1){
            try {
                return json.getJSONObject("data").getJSONObject("1").getInteger("singerid");
            }catch (NullPointerException e){
                return null;
            }
        }
        return null;
    }


    /**
     * 查询歌手信息
     * @param id
     * @return
     */
    @Cacheable("KugouService")
    public Singer querySingerInfo(Integer id){
        String response = HttpClientUtil.getData(KUGOU_QUERY_SINGER_INFO_URL, id);
        JSONObject data = JSONObject.parseObject(response).getJSONObject("data");
        if(data == null)
            return null;

        Singer singer = new Singer();
        singer.setId(data.getInteger("singerid"));
        singer.setName(data.getString("singername"));
        singer.setAvatarUrl(data.getString("imgurl").replace("http://singerimg.kugou.com/","https://imgessl.kugou.com/").replace("{size}","480"));
        singer.setProfile(data.getString("profile"));
        return singer;
    }

    /**
     * 查询专辑信息
     * @param albumId
     * @return
     */
    @Cacheable("KugouService")
    public Album queryAlbumInfo(Integer albumId){
        String response = HttpClientUtil.getData(KUGOU_QUERY_ALBUM_INFO_URL, albumId);
        JSONObject data = JSONObject.parseObject(response).getJSONObject("data");
        Album album = new Album();
        album.setId(albumId);
        album.setName(data.getString("albumname"));
        album.setAvatarUrl(data.getString("imgurl").replace("http://imge.kugou.com/", "https://imgessl.kugou.com/").replace("{size}", "480"));
//        album.setSingerId(data.getInteger("singerid"));
        try {
            album.setPublishTime(data.getDate("publishtime"));
        } catch (NumberFormatException e) {
            album.setPublishTime(DateUtil.NULL_DATE);
        }
        album.setIntro(data.getString("intro"));
        return album;
    }

    /**
     * 获取歌曲的下载信息
     * @param hash
     * @return
     */
    @Cacheable("KugouService")
    public MusicDownloadInfo queryMusicDownloadUrl(String hash){
        String response = HttpClientUtil.getData(KUGOU_DOWNLOAD_MUSIC_URL,new HashMap<String, Object>(){{
            put("cmd","26");
            put("pid","4");
            put("authType","1");
            put("hash",hash);
            //加密算法来自 https://blog.csdn.net/qiuxy23/article/details/81266030
            put("key",EncryptUtil.md5(hash + "kgcloudv2"+ KUGOU_CONFIG_APP_ID + KUGOU_CONFIG_MID + KUGOU_CONFIG_USER_ID));
            put("behavior","play");
            put("module","collection");
            put("appid",KUGOU_CONFIG_APP_ID);
            put("mid",KUGOU_CONFIG_MID);
            put("userid",KUGOU_CONFIG_USER_ID);
            put("token",getToken());
            put("version","2.9.5");
            put("vipType","6");
        }});
        JSONObject json = JSONObject.parseObject(response);
        if(json.getInteger("status") == 1){
            return new MusicDownloadInfo(json.getJSONArray("url").getString(0),json.getString("extName"));
        }
        return new MusicDownloadInfo(true);
    }

    /**
     * 查询专辑内的所有歌曲名称
     * @param albumId
     * @return
     */
    @Cacheable("KugouService")
    public List<Song> querySongListInAlbum(Integer albumId){
        String html = HttpClientUtil.getData(KUGOU_QUERY_ALBUM_INCLUDES_URL,albumId);
        String[] htmlLines = html.split("\r\n");
        String bigJSON = "[]";
        for (String line : htmlLines) {
            if(StringUtils.startsWith(line,"\tglobal.data = [")){
                bigJSON = line.replace("\tglobal.data = ","").replace("}];","}]");
                break;
            }
        }
        List<Song> songList = new ArrayList<>();
        try {
            JSONArray jsonArray = JSONArray.parseArray(bigJSON);
            jsonArray.forEach(obj -> {
                JSONObject item = (JSONObject) obj;
                Song song = new Song();
                song.setId(item.getInteger("audio_id"));
                song.setName(item.getString("audio_name"));
                song.setHash(item.getString("hash"));
                song.setSqHash(item.getString("hash_flac"));
                song.setHqHash(item.getString("hash_320"));
                song.setDuration(item.getInteger("duration") / 1000);
                song.setMvHash(item.getString("mv_hash"));
                songList.add(song);
//                querySongObjectInfo(null,item.getInteger("audio_id"));
            });
            //如果出线无法解析JSON 该专辑无版权 没有歌曲列表
        }catch (JSONException ignored){}
        return songList;
    }


    /**
     * 查询歌手的所有专辑
     * @param singerId
     * @return
     */
    @Cacheable("KugouService")
    public List<Album> querySingerAlbumList(Integer singerId){
        List<Album> albumList = new ArrayList<>();
        String response = HttpClientUtil.getData(KUGOU_QUERY_SINGER_ALBUM_LIST_URL, singerId);
        JSONObject.parseObject(response).getJSONObject("data").getJSONArray("info").forEach(obj -> {
            JSONObject item = (JSONObject) obj;
            Album album = new Album();
            album.setId(item.getInteger("albumid"));
            album.setName(item.getString("albumname"));
            album.setAvatarUrl(item.getString("imgurl").replace("http://imge.kugou.com/", "https://imgessl.kugou.com/").replace("{size}", "480"));
//            album.setSingerId(item.getInteger("singerid"));
            album.setPublishTime(item.getDate("publishtime"));
            album.setIntro(item.getString("intro"));
            albumList.add(album);
        });
        return albumList;
    }


    /**
     * 查询歌单分享数据
     * @param url
     * @return
     */
    @Cacheable("KugouService")
    public SongListShare queryShareURLData(String url){
        //必须拿微信的UA去模拟访问 否则会跳转到PC页面
        String location = new HttpClientUtil(url)
                .setHeader("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.11(0x17000b21) NetType/WIFI Language/zh_CN")
                .noFollowRedirects()
                .exec()
                .getResponseHeader("Location");
        String args = location.split("zlist.html")[1];
        String response = HttpClientUtil.getData(KUGOU_QUERY_SHARE_URL_INFO_URL + args + "&page=1&pagesize=100000");
        JSONObject jsonObject = JSONObject.parseObject(response);

        JSONObject info = (JSONObject) jsonObject.getJSONArray("info").get(0);
        SongListShare share = new SongListShare(){{
            //创建歌单用户信息
            setUserId(info.getLong("list_create_userid"));
            setUserName(info.getString("list_create_username"));
            setUserAvatarUrl(info.getString("list_create_headimg"));
            //歌单信息
            setName(info.getString("name"));
            setCreateTime(new Date(info.getLong("create_time") * 1000));
            setIntro(info.getString("intro"));
            setTags(info.getString("tags"));
        }};

        jsonObject.getJSONObject("list").getJSONArray("info").forEach(object0 -> {
            JSONObject object = (JSONObject) object0;
            share.addHash(object.getString("hash"));
            share.addAlbum(object.getInteger("album_id"));
        });

        return share;
    }

    /**
     * 查询歌曲演唱者列表
     * @param hash
     * @return
     */
    @Cacheable("KugouService")
    public List<Tag> querySongTagList(String hash){
        List<Tag> tagList = new ArrayList<>();

        JSONObject data = querySongObjectInfo(hash);
        if(data == null)
            return tagList;

        JSONObject info = data.getJSONObject("audio_info");
        //添加标签信息 部分歌曲没有添加标签
        try{
            info.getJSONArray("tags").forEach(object0 -> {
                JSONObject tag0  = (JSONObject) object0;
                Tag tag = new Tag();
                tag.setId(tag0.getInteger("tag_id"));
                tag.setName(tag0.getString("tag_name"));
                tag.setParentId(tag0.getInteger("parent_id"));
                tagList.add(tag);
            });
        }catch (ClassCastException ignored){}
        return tagList;
    }


    @Cacheable("KugouService")
    public SongDTO querySongInfo(String hash){
        SongDTO song = new SongDTO();
        JSONObject data = querySongObjectInfo(hash);
        if(data == null)
            return null;
        //设置基本信息
        song.setId(data.getInteger("audio_id"));
        song.setLanguage(data.getString("language"));
        song.setName(data.getString("songname"));
        JSONObject info = data.getJSONObject("audio_info");
        //添加歌曲音质信息
        song.setHash(info.getString("hash"));
        song.setHqHash(info.getString("hash_320"));
        song.setSqHash(info.getString("hash_flac"));

        List<String> singerList = new ArrayList<>();
        data.getJSONArray("authors").forEach(obj0 -> {
            JSONObject singer = (JSONObject) obj0;
            singerList.add(singer.getString("author_name"));
        });
        song.setSingerName(String.join("、",singerList));
        song.setAlbumName(data.getJSONObject("album_info").getString("album_name"));

        return song;
    }

    @Cacheable("KugouService")
    public List<Singer> querySingerListBySongHash(String hash){
        List<Singer> singerList = new ArrayList<>();
        JSONObject data = querySongObjectInfo(hash);
        //添加歌手信息
        try{
            data.getJSONArray("authors").forEach(object0 -> {
                JSONObject author = (JSONObject) object0;
                Singer singer = new Singer();
                singer.setId(author.getInteger("author_id"));
                singer.setName(author.getString("author_name"));
                singerList.add(singer);
            });
            //如果歌手信息为空 数据问题 不需要解决
        }catch (ClassCastException ignored){}

        return singerList;
    }

    @Cacheable("KugouService")
    public JSONObject querySongObjectInfo(Object arg){
        String hash = null;
        Integer songId=null;
        if(arg instanceof String)
            hash = (String) arg;
        else if (arg instanceof Integer)
            songId = (Integer) arg;
        else
            return null;
        Integer finalSongId = songId;
        String finalHash = hash;
        Map<String,Object> entity = new HashMap<String, Object>(){{
            put("data",
                    new ArrayList<Object>(){{
                        add(
                                new HashMap<String,Object>(){{
                                    put("hash",null == finalHash ? "" : finalHash);
                                    put("audio_id",null == finalSongId ? "" : finalSongId);
                                    put("filename","");
                                }}
                        );
                    }}
            );
            put("appid",KUGOU_CONFIG_APP_ID);
            put("mid",KUGOU_CONFIG_MID);
            put("clientver",295);
            put("clienttime",System.currentTimeMillis());
            //这个接口没有对key进行校验。这个BUG不知道什么时候修复
            put("key", "NO_EXIST_KEY");
        }};
        String response = HttpClientUtil.postJson(KUGOU_QUERY_SONG_SINGER_LIST_URL,entity);
        try {
            return JSONObject.parseObject(response).getJSONArray("data").getJSONArray(0).getJSONObject(0);
        }catch (ClassCastException ignored){
            //无法获取信息
            return null;
        }
    }

    /**
     * 获取当前token
     * @return
     */
    public String getToken(){
        String token;
        if((token = cacheOperator.get(CacheKeys.KUGOU_LOGIN_TOKEN)) == null){
            Map<String,Object> args = new HashMap<String, Object>(){{
                put("appid",KUGOU_CONFIG_APP_ID);
                put("username",username);
                put("pwd",password);
                put("code","");
                put("ticket","");
                put("clienttime",System.currentTimeMillis() / 1000);
                //为了防止token提前过期 这里设置10天
                put("expire_day",10);
                put("autologin",true);
                put("redirect_uri","");
                put("state",1);
                put("callback","callback");
                put("login_ver",1);
                put("mobile","");
                put("mobile_code","");
                //这里的mid和通用的mid不一样 使用通用的mid就会提示手机号？？？
                put("mid","7429557b444d2788f356d1c4aaaf9dc5");
                put("kguser_jv","12121");
            }};
            String response = HttpClientUtil.getData(KUGOU_LOGIN_URL, args)
                    //去掉回调部分代码 转换为完整JSON
                    .replace("callback(", "")
                    .replace("})", "}");
            token =  JSONObject.parseObject(response).getString("token");
            cacheOperator.set(CacheKeys.KUGOU_LOGIN_TOKEN,token, DateUtil.DAYS / 1000 * 10);
        }
        return token;
    }


    @Cacheable("KugouService")
    public String queryMvPlayUrl(String mvHash){
        mvHash = mvHash.toUpperCase();
        String url = null;
        String key = EncryptUtil.md5(mvHash + "kugoumvcloud");
        String response = HttpClientUtil.getData(KUGOU_QUERY_MV_PLAY_URL, mvHash, key);
        JSONObject mvData = JSONObject.parseObject(response).getJSONObject("mvdata");
        for (String type:Arrays.asList("hd","sd","rq","sq")) {
            if(null != (url = queryMVUrl.apply(mvData,type)))
                break;
        }
        return url;
    }

    public String queryPlayUrlWithSSL(String hash){
        String response = HttpClientUtil.getData(KUGOU_QUERY_SONG_PLAY_URL_WITH_SSL, hash);
        JSONObject jsonObject = JSONObject.parseObject(response);
        if(jsonObject.getInteger("status") != 1)
            throw new RuntimeException("query hash failed");
        return jsonObject.getJSONObject("data").getString("play_url");
    }

    /**
     * 查询歌曲演唱ID列表
     * @param hash
     * @return
     */
    public List<Integer> querySingerList(String hash){
        List<Integer> singerList = new ArrayList<>();
        String response = HttpClientUtil.getData(KUGOU_QUERY_SONG_PLAY_URL_WITH_SSL, hash);
        JSONObject jsonObject = JSONObject.parseObject(response);
        if(jsonObject.getInteger("status") != 1)
            throw new RuntimeException("query hash failed");
        jsonObject.getJSONObject("data").getJSONArray("authors").forEach(object0 -> {
            JSONObject object = (JSONObject) object0;
            singerList.add(object.getIntValue("author_id"));
        });
        return singerList;
    }

}
